﻿global using Devonline.Core;
global using Devonline.Entity;
using System.Linq.Expressions;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Primitives;

namespace Devonline.AspNetCore;

/// <summary>
/// 公共数据处理服务, 此类服务不提交数据库上下文
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TKey">键类型</typeparam>
public interface IServiceBase<TDbContext, TKey>
    where TDbContext : DbContext
    where TKey : IConvertible
{
    #region 基础成员
    /// <summary>
    /// TypeAdapterConfig 类型隐射实例
    /// </summary>
    TypeAdapterConfig AdapterConfig { get; init; }
    /// <summary>
    /// Gets or sets a flag indicating if changes should be persisted after CreateAsync, 
    /// UpdateAsync and DeleteAsync are called.
    /// True if changes should be automatically persisted, otherwise false.
    /// </summary>
    bool AutoSaveChanges { get; set; }
    /// <summary>
    /// 当前登录的用户名
    /// </summary>
    string UserName { get; }
    /// <summary>
    /// 从 httpContext 获取用户标识, 用户标识在 User.Claims 中的 type 为 sub; 在 request 中为 userId
    /// </summary>
    /// <returns></returns>
    string? GetUserId();
    /// <summary>
    /// 从 httpContext 获取用户名, 用户名在 User.Claims 中的 type 为 UserName;
    /// </summary>
    /// <returns></returns>
    string? GetUserName();
    /// <summary>
    /// 获取查询选项列表
    /// </summary>
    /// <returns>返回合并后的查询选项</returns>
    IEnumerable<KeyValuePair<string, StringValues>> GetRequestOptions();
    /// <summary>
    /// 从当前 request 中获取参数的值, 取值顺序 Query -> Form -> Header -> Cookie
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    T? GetRequestOption<T>(string key) where T : IConvertible;
    /// <summary>
    /// 获取上下文对象中参数/变量的值, 取值顺序 HttpContext -> Query -> Form -> Header -> Cookie
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    T? GetContextOption<T>(string key) where T : IConvertible;
    /// <summary>
    /// 获取附件绝对地址
    /// </summary>
    /// <param name="fileName">附件文件名</param>
    /// <returns></returns>
    string GetAttachmentPath(string fileName);
    /// <summary>
    /// 获取随机的临时文件名
    /// </summary>
    /// <param name="extension"></param>
    /// <returns></returns>
    string GetTempFileName(string? extension = default);
    /// <summary>
    /// 获取 TypeAdapterConfig 默认实例
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <returns></returns>
    TypeAdapterConfig GetAdapterConfig<TEntitySet>();
    /// <summary>
    /// 调用实例的 Create 方法为基础字段赋值
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="entitySet"></param>
    void Create<TEntitySet>(TEntitySet entitySet);
    /// <summary>
    /// 调用实例的 Update 方法为基础字段赋值
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="entitySet"></param>
    void Update<TEntitySet>(TEntitySet entitySet);
    /// <summary>
    /// 从当前上下文解除当前对象的跟踪状态
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    void Detach<TEntitySet>(TEntitySet entitySet) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 逻辑修改
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    void Update<TEntitySet>(TEntitySet entitySet, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 逻辑删除
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    void Delete<TEntitySet>(TEntitySet entitySet, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 提交当前操作
    /// </summary>
    /// <returns></returns>
    Task<int> SaveChangesAsync();
    /// <summary>
    /// 刷新缓存
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <returns></returns>
    Task RefreshCacheAsync<TEntitySet>() where TEntitySet : class;
    #endregion

    #region 数据查询方法
    /// <summary>
    /// 非注入类型 TEntity 统一数据源查询入口, 可缓存数据源, 可返回泛型类型指定的任意类型引用
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <returns></returns>
    IQueryable<TEntitySet> GetQueryable<TEntitySet>() where TEntitySet : class;
    /// <summary>
    /// 非注入类型 TEntity 统一数据源查询入口, 可缓存数据源, 可返回泛型类型指定的任意类型引用
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="predicate">过滤条件</param>
    /// <returns></returns>
    IQueryable<TEntitySet> GetQueryable<TEntitySet>(Expression<Func<TEntitySet, bool>> predicate) where TEntitySet : class;
    /// <summary>
    /// 根据 id 获取对象
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="id"></param>
    /// <returns></returns>
    Task<TEntitySet?> GetAsync<TEntitySet>(TKey id) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 从 QueryOptions 和上下文自动获取查询表达式的内容并执行查询返回分页的结果
    /// 暂不支持 orderby, select 和 expand 表达式
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <returns></returns>
    Task<PagedResult> GetPagedResultAsync<TEntitySet>() where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 适用于新增时判断对象是否存在, 存在则抛出异常
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="id">业务数据编号</param>
    /// <returns></returns>
    /// <exception cref="BadHttpRequestException"></exception>
    Task ThrowIfExistAsync<TEntitySet>(TKey? id) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 适用于更新时判断当前对象是否存在, 存在则返回按 Id 查询的结果, 不存在则抛出异常
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <returns></returns>
    /// <exception cref="BadHttpRequestException"></exception>
    Task<TEntitySet> GetIfExistAsync<TEntitySet>(TKey id) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 获取业务数据的集合成员, 成员是附加信息, 附件及特定类型的附属集合
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TElement">附加信息, 附件或附属集合的类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    IEnumerable<TElement>? GetCollectionMembers<TEntitySet, TElement>(TEntitySet entitySet) where TEntitySet : class, IEntitySet<TKey> where TElement : class, IEntitySet<TKey>;
    #endregion

    #region 数据操作方法
    /// <summary>
    /// 新增或修改阶段判断满足条件的数据是否存在, 存在则抛出异常, 不存在则执行基类预定义赋值操作
    /// </summary>
    /// <typeparam name="TEntitySet">查询的类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    /// <exception cref="BadHttpRequestException"></exception>
    Task UniqueAsync<TEntitySet>(TEntitySet entitySet) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 单个数据对象的新增, 自动验证重复
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TEntitySet>(TEntitySet entitySet) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 单个数据对象的更新, 自动验证重复
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TEntitySet>(TEntitySet entitySet, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey>;
    /// <summary>
    /// 删除记录
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TEntitySet>(TKey id, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey>;
    #endregion

    #region 数据带附属信息的数据操作方法
    #region 新增部分
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息一并新增
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TEntitySet, TAdditional>(TEntitySet entitySet) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附件一并新增
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TEntitySet, TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default) where TEntitySet : class, IEntitySet<TKey> where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的的某一种集合成员一并新增
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TEntitySet, TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TEntitySet : class, IEntitySet<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息及附件一并新增
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TEntitySet, TAdditional, TAttachment>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TEntitySet, TAdditional, TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TEntitySet : class, IEntitySet<TKey> where TElement : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附件及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TEntitySet, TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TEntitySet : class, IEntitySet<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息, 附件及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TEntitySet, TAdditional, TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    #endregion

    #region 修改部分
    /// <summary>
    /// 重载的更新方法会同时将当前类型的附加信息一并更新
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TEntitySet, TAdditional>(TEntitySet entitySet, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附件一并更新
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TEntitySet, TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TEntitySet, TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息及附件一并更新
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TEntitySet, TAdditional, TAttachment>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TEntitySet, TAdditional, TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附件及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet"></param>
    /// <param name="attachments"></param>
    /// <param name="elements"></param>
    /// <param name="foreignKey"></param>
    /// <param name="isLogical"></param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TEntitySet, TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息, 附件及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TEntitySet, TAdditional, TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    #endregion

    #region 删除部分
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息一并删除
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <param name="additionalId">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TEntitySet, TAdditional>(TKey additionalId, IEnumerable<TAdditional>? additionals = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附件一并删除
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="businessKey">业务主键</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TEntitySet, TAttachment>(TKey businessKey, string? businessType = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TEntitySet, TElement>(TKey id, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息及附件一并删除
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TEntitySet, TAdditional, TAttachment>(TKey id, IEnumerable<TAdditional>? additionals = default, string? businessType = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息及业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TEntitySet, TAdditional, TElement>(TKey id, IEnumerable<TAdditional>? additionals = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附件及业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TEntitySet, TAttachment, TElement>(TKey id, string? businessType = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息, 附件及业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TEntitySet, TAdditional, TAttachment, TElement>(TKey id, IEnumerable<TAdditional>? additionals = default, string? businessType = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    #endregion    
    #endregion

    #region 业务附加信息类操作方法
    /// <summary>
    /// 新增业务数据的附加信息
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <returns></returns>
    Task AddAdditionalsAsync<TEntitySet, TAdditional>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey>;
    /// <summary>
    /// 更新业务数据的附加信息
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task UpdateAdditionalsAsync<TEntitySet, TAdditional>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey>;
    /// <summary>
    /// 删除业务数据的附加信息
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <param name="additionalId">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAdditionalsAsync<TAdditional>(TKey additionalId, IEnumerable<TAdditional>? additionals = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey>;
    #endregion

    #region 业务数据引用关系的集合类操作方法
    /// <summary>
    /// 新增业务数据对象中 TElement 类型的集合对象
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">引用数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    Task AddCollectionAsync<TEntitySet, TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TEntitySet : class, IEntitySet<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 更新业务数据对象中 TElement 类型的集合对象
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">引用数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task UpdateCollectionAsync<TEntitySet, TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 删除业务数据对象中 TElement 类型的集合对象
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="elements">引用数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteCollectionAsync<TEntitySet, TElement>(TKey id, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TElement : class, IEntitySet<TKey>;
    #endregion

    #region 文件及业务数据附件操作方法
    /// <summary>
    /// 获取并返回文件名指向的物理文件
    /// </summary>
    /// <param name="fileName">文件名</param>
    /// <returns></returns>
    IActionResult GetFile(string fileName);
    /// <summary>
    /// 文件下载, 提供类似于文件夹目录结构的访问方式进行下载
    /// 形如 2020-01-01/xxx.jpg
    /// </summary>
    /// <param name="fileName">文件名</param>
    /// <param name="filePath">文件路径</param>
    /// <returns></returns>
    Task<TAttachment?> GetAttachmentAsync<TAttachment>(string? fileName, string? filePath = default) where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 获取附件对应的文件, 适用于文件下载
    /// 形如 2020-01-01/xxx.jpg
    /// </summary>
    /// <param name="fileName">文件名</param>
    /// <param name="filePath">文件路径</param>
    /// <returns></returns>
    Task<IActionResult> GetAttachmentFileAsync<TAttachment>(string? fileName, string? filePath = default) where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 获取文件, 按业务类型和业务主键获取
    /// </summary>
    /// <param name="businessType">业务类型</param>
    /// <param name="businessKey">业务主键</param>
    /// <returns></returns>
    Task<IEnumerable<TAttachment>?> GetAttachmentsAsync<TAttachment>(string? businessType = default, TKey? businessKey = default) where TAttachment : class, IAttachment<TKey>;

    /// <summary>
    /// 单个文件上传
    /// </summary>
    /// <param name="file"></param>
    /// <returns></returns>
    Task<UploadResult<TAttachment, TKey>> UploadAsync<TAttachment>(IFormFile? file = default) where TAttachment : class, IAttachment<TKey>, new();
    /// <summary>
    /// 批量文件上传
    /// </summary>
    /// <param name="files"></param>
    /// <returns></returns>
    Task<IEnumerable<UploadResult<TAttachment, TKey>>> UploadAsync<TAttachment>(IEnumerable<IFormFile>? files = default) where TAttachment : class, IAttachment<TKey>, new();

    /// <summary>
    /// 删除附件物理文件, 请在附件相关操作的事物提交之后执行此方法
    /// </summary>
    /// <param name="files">待删除的文件</param>
    void Delete(IEnumerable<string> files);

    /// <summary>
    /// 新增附件
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件集合</param>
    /// <param name="businessType">业务类型</param>
    /// <returns>待删除文件列表, 请在数据库事物提交成功后删除列表中的文件</returns>
    Task AddAttachmentsAsync<TEntitySet, TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, string? businessType = default) where TEntitySet : class, IEntitySet<TKey> where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 修改附件, 保留旧附件, 新增新附件, 返回待删除文件列表
    /// </summary>
    /// <typeparam name="TEntitySet">业务数据类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件集合</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns>待删除文件列表, 请在数据库事物提交成功后删除列表中的文件</returns>
    Task<IEnumerable<string>> UpdateAttachmentsAsync<TEntitySet, TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, string? businessType = default, bool isLogical = false) where TEntitySet : class, IEntitySet<TKey> where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 自动删除附件, 返回待删除文件列表, 适用于实体对象模型从数据库删除时查找原始附件并自动删除
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="businessKey">业务主键</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns>待删除文件列表, 请在数据库事物提交成功后删除列表中的文件</returns>
    Task<IEnumerable<string>?> DeleteAttachmentsAsync<TAttachment>(TKey businessKey, string? businessType = default, bool isLogical = false) where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 按文件列表删除附件
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="fileNames">待删除的文件名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<IEnumerable<string>?> DeleteAttachmentsAsync<TAttachment>(IEnumerable<string> fileNames, bool isLogical = false) where TAttachment : class, IAttachment<TKey>;
    #endregion
}

/// <summary>
/// 字符串作为主键的默认实现接口
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
public interface IServiceBase<TDbContext> : IServiceBase<TDbContext, string> where TDbContext : DbContext { }